# https://zhuanlan.zhihu.com/p/75872830?from_voters_page=true 函数作用
# 未完成：有人退出时clientsocket列表中无法空出位置，也不能更新玩家个数
# 视野模块 击杀消息显示
from socket import *
from tkinter import *
from tkinter.ttk import *#combobox需要
try:
    from _thread import *
except:
    from thread import *
from queue import Queue
from random import *
import time
from os import *

#init
P=8 #最大玩家数
m=10
n=10 #地图行/列
denofcastle=9
denofmount=9
denofswamp=0
numofpls=0
sta=0
numofdieplayer=0
turn=0
# whedist=0
M=5 #大本营间最近曼哈顿距离 待改
color=['grey','red','blue','green','yellow','purple','pink','cyan','orange']

class Block:
    def __init__(self,ty):
        self.type=int(ty) #0地 1山 2塔 3大本营 4沼泽
        self.army=0
        self.color=0
        if self.type==2:
            self.army=choice(range(40,50))
        self.lazytag=True  
map=[0]
for i in range(1,n+1):
    map.append([0])
    for j in range(1,m+1):
        map[i].append(0);
player=[0]
class Players:
    def __init__(self,nn):
        self.die=False
        self.color=nn
        self.army=1
        self.land=1
        self.castle=1
        self.operate=Queue(maxsize=N)
        con=1
        while con:
            x = choice(range(1,n+1))
            y = choice(range(1,m+1))
            if(map[x][y].type!=0):continue
            for i in range(1, nn - 1 + 1):
                xa=player[i].home[0]
                ya=player[i].home[1]
                if (abs(xa - x) + abs(ya - y) <= M):
                    break
            else:
                con=0
                self.home=(x,y)
                self.highlight = [x,y]
                map[x][y].type=3
                map[x][y].color=nn
                map[x][y].army=1
    def kill(self,p):# 俘获玩家p (函数名改成capture?)
        # 修改player.army,land!!
        global numofdieplayer
        map[player[p].home[0]][player[p].home[1]].type=2
        for i in range(1,n+1):
            for j in range(1,m+1):
                if(map[i][j].color==p):
                    map[i][j].color=self.color
                    map[i][j].army=(map[i][j].army+1)//2
                   # map[i][j].lazytag=True
        player[p].die=True
        numofdieplayer+=1

#操作定义
def gameover():
    sendd()
    return
class Move:
    def __init__(self):
        fx=0
        fy=0
        tx=0
        ty=0
move=Move()
def mov(m):
    mover,move.fx,move.fy,move.tx,move.ty,movenum=m
    if player[mover].die: return
    '''
    if player[mover].operate.empty(): continue
    move=player[mover].operate.get(False)
    if map[move.tx][move.ty].type==1: continue#
    if map[move.fx][move.fy].color!=mover: continue#
    movenum=int(move.num*map[move.fx][move.fy].army)
    if movenum==map[move.fx][move.fy].army: movenum-=1
    if movenum==0: continue#
    '''
    map[move.fx][move.fy].lazytag=True
    map[move.tx][move.ty].lazytag=True
    map[move.fx][move.fy].army-=movenum
    if (map[move.tx][move.ty].type==0 or map[move.tx][move.ty].type==4):        # 平地or沼泽
        if map[move.tx][move.ty].color==0:                                          #无归属
            map[move.tx][move.ty].army+=movenum
            map[move.tx][move.ty].color=player[mover].color
            player[mover].land+=1
        elif map[move.tx][move.ty].color==player[mover].color:                      #己方
            map[move.tx][move.ty].army+=movenum
        else:                                                                       #敌方
            if movenum>map[move.tx][move.ty].army:                                      #占领
                map[move.tx][move.ty].army=movenum-map[move.tx][move.ty].army
                player[mover].army-=movenum-map[move.tx][move.ty].army
                player[mover].land+=1
                player[map[move.tx][move.ty].color].army-=movenum-map[move.tx][move.ty].army
                player[map[move.tx][move.ty].color].land-=1
                map[move.tx][move.ty].color=player[mover].color
            else:                                                                       #未占领
                map[move.tx][move.ty].army-=movenum
                player[mover].army-=movenum
                player[map[move.tx][move.ty].color].army-=movenum
                
    else:                                                                       # 塔or大本营
        if map[move.tx][move.ty].color==0:                                          #无归属
            if movenum>map[move.tx][move.ty].army:                                      #占领
                map[move.tx][move.ty].army=movenum-map[move.tx][move.ty].army
                map[move.tx][move.ty].color=player[mover].color
                player[mover].army-=movenum-map[move.tx][move.ty].army
                player[mover].land+=1
                player[mover].castle+=1
            else:                                                                       #未占领
                map[move.tx][move.ty].army-=movenum
                player[mover].army-=movenum
        elif map[move.tx][move.ty].color==player[mover].color:                      #己方
            map[move.tx][move.ty].army+=movenum
        else:                                                                       #敌方
            if movenum>map[move.tx][move.ty].army:                                      #占领
                player[mover].army-=movenum-map[move.tx][move.ty].army
                player[mover].land+=1
                player[mover].castle+=1
                player[map[move.tx][move.ty].color].army-=movenum-map[move.tx][move.ty].army
                player[map[move.tx][move.ty].color].land-=1
                player[map[move.tx][move.ty].color].castle-=1
                if(map[move.tx][move.ty].type==3): player[mover].kill(map[move.tx][move.ty].color) #占领大本营则消灭敌人
                map[move.tx][move.ty].army=movenum-map[move.tx][move.ty].army
                map[move.tx][move.ty].color=player[mover].color
            else:                                                                       #未占领
                map[move.tx][move.ty].army-=movenum
                player[mover].army-=movenum
                player[map[move.tx][move.ty].color].army-=movenum

#编码/发送信息
def encB(i,j):
    msg='B'+chr(i)+chr(j)+chr(map[i][j].army//100)+chr(map[i][j].army%100)+chr(map[i][j].color)+chr(map[i][j].type)
    return msg
    
def encP(i):
    msg='P'+chr(i)+chr(player[i].army//100)+chr(player[i].army%100)+chr(player[i].land//100)+chr(player[i].land%100)+chr(player[i].castle//100)+chr(player[i].castle%100)
    return msg

def sendmsg(p,s):
    clientsocket[p].send(s.encode("ASCII"))
    return

#解码/接收信息
def dec(msg):
    p=msg[1]
    fx=msg[2]
    fy=msg[3]
    tx=msg[4]
    ty=msg[5]
    num=msg[6]*100+msg[7]
    return (p,fx,fy,tx,ty,num)
def rec():
    print('rec')
    for i in range(1,numofpls+1):
        msg=clientsocket[i].recv(8)
        mov(dec(msg.decode("ASCII")))
        
#网络连接
serversocket = socket(AF_INET,SOCK_STREAM)
host = gethostname()
port = 12345
serversocket.bind((host,port))
serversocket.listen(P)

csocket = socket(AF_INET,SOCK_STREAM)
clientsocket = [csocket]
addr = [0]

def connecter():
    global numofpls
    while sta==0:
        csocket,ad = serversocket.accept()
        clientsocket.append(csocket)
        addr.append(ad)
        numofpls+=1
        welcome="Connect Successfully!"+"There's " + str(numofpls) +" player(s) ready."+"Please wait for other players."
        clientsocket[numofpls].send(welcome.encode("utf-8"))
        curpls.configure(text="There's " + str(numofpls) +" player(s) ready.")

start_new_thread(connecter,())

#编码 解码 发送 接收
def sendd():
    print('sendd')
    for i in range(1,numofpls+1):
        for j in range(1,numofpls+1):
            sendmsg(i,encP(j))
    for i in range(1,n+1):
        for j in range(1,m+1):
            if(map[i][j].lazytag==True):
                for pla in range(1,numofpls+1):
                    sendmsg(pla,encB(n,m))
    return

#控件设置
def start(): # 这里写主程序
    # if numofpls<2: return
    n = int(spinn.get())
    m = int(spinm.get())
    denofcastle = int(spincastle.get())
    denofmount = int(spinmount.get())
    denofswamp = int(spinswamp.get())
    fd=open('g.in',O_RDWR)
    write(fd,str.encode(str(n)+' '+str(m)+' '+str(m*n*denofmount/100)+' '+str(m*n*denofcastle/100)+' '+str(m*n*denofswamp/100)))
    close( fd )
    sta = 1
    # whedist = combdist.get()#是否使用曼哈顿距离
    window.destroy()
    system("start /wait Generals_map_init.exe")
    for i in range(1,n+1):
        inp=input().split()
        print(inp)
        for j in range(1,m+1):
            map[i][j]=(Block(inp[j-1]))
    for i in range(1,numofpls+1):
        player.append(Players(i))
        clientsocket[i].send(str("S").encode("ASCII"))#发送开始信息
   # print(whedist)
   # 主进程
    global turn
    while numofdieplayer<numofpls-1:
        turn+=1
        for rsx in range(2):
            print('?')
            sendd() # 发送地图信息
            time.sleep(0.5)
            rec()
            print('!')
        #更新士兵数目
        for i in range(1,n+1):
            for j in range(1,m+1):
                if (map[i][j].color!=0 and (map[i][j].type==2 or map[i][j].type==3)):
                    map[i][j].army+=1
                    player[map[i][j].color].army+=1
                    map[i][j].lazytag=True
                if (turn%25==0 and map[i][j].color!=0):
                    map[i][j].army+=1
                    player[map[i][j].color].army+=1
                    map[i][j].lazytag=True
                if (map[i][j].type==4 and map[i][j].army!=0):
                    map[i][j].army-=1
                    player[map[i][j].color].army-=1
                    if map[i][j].army==0:
                        player[map[i][j].color].land-=1
                        map[i][j].color=0
                    map[i][j].lazytag=True
    gameover()

window = Tk() # 建立窗口
window.title("Generals_Server")
notice = Label(window,text="Please reset the map if you want.") 
curpls = Label(window,text=str(numofpls) +" player(s) ready.")
hst = Label(window,text="Your hostname is " + str(host) +" .")
go = Button(window,text="Go!",command=start)
labn = Label(window,text="height")
labm = Label(window,text="width")
labcastle = Label(window,text="castle density")
labmount = Label(window,text="mount density")
labswamp = Label(window,text="swamp density")
labcent1 = Label(window,text="%")
labcent2 = Label(window,text="%")
labcent3 = Label(window,text="%")
labdist = Label(window,text="Avoid the homes crowded")
n_state = IntVar()
m_state = IntVar()
castle_state = IntVar()
mount_state = IntVar()
swamp_state = IntVar()
# dist_state = IntVar()
n_state.set(n)
m_state.set(m)
castle_state.set(denofcastle)
mount_state.set(denofmount)
swamp_state.set(denofswamp)
# dist_state.set(N)
spinn = Spinbox(window,from_=10,to=50,textvariable=n_state)
spinm = Spinbox(window,from_=10,to=50,textvariable=m_state)
spincastle = Spinbox(window,from_=0,to=18,textvariable=castle_state)
spinmount = Spinbox(window,from_=0,to=18,textvariable=mount_state)
spinswamp = Spinbox(window,from_=0,to=18,textvariable=swamp_state)
# combdist = Combobox(window)
# combdist['values'] = ("Off","On")
# combdist.current(1)

#控件安放
notice.grid(column=1,row=1)
hst.grid(column=1,row=2)
curpls.grid(column=1,row=3)
labn.grid(column=1,row=4)
spinn.grid(column=2,row=4)
labm.grid(column=1,row=5)
spinm.grid(column=2,row=5)
labcastle.grid(column=1,row=6)
spincastle.grid(column=2,row=6)
labcent1.grid(column=3,row=6)
labmount.grid(column=1,row=7)
spinmount.grid(column=2,row=7)
labcent2.grid(column=3,row=7)
labswamp.grid(column=1,row=8)
spinswamp.grid(column=2,row=8)
labcent3.grid(column=3,row=8)
# labdist.grid(column=1,row=9)
# combdist.grid(column=2,row=9)
go.grid(column=1,row=9)
go.focus()
window.mainloop()
while True : pass
